﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Gfw.Infrastructure.Stock.Enums;
using Gfw.Infrastructure.Stock.Facilities;
using Gfw.Models.Stock;
using Gfw.Repositories.Stock;
using Gfw.Repository;

namespace StockWcf.Manager
{
    public class AgencyProxy
    {
        public string AgencyId { get; set; }
        public DateTime TimeStamp { get; set; }
    }

    public static class TradeManager
    {
        #region 变量和属性
        private static object waitLock = new object();
        public static object excuteLock = new object();
        private static object cancelLock = new object();
        private static bool waitExecute = false;
        private static DateTime LoadTimeStamp;

        private static bool WaitExecute
        {
            get
            {
                lock (waitLock)
                {
                    return TradeManager.waitExecute;
                }
            }
            set
            {
                lock (waitLock)
                {
                    TradeManager.waitExecute = value;

                }
            }
        }

        #endregion

        #region 公开的方法

        public static void Execute()
        {
            if (WaitExecute == false)
            {
                WaitExecute = true;
                Thread th = new Thread(_Execute);
                th.Start();
            }
        }



        #endregion

        #region 股票交易

        private static void _Execute()
        {
            lock (excuteLock)
            {
                WaitExecute = false;
                var pools = GetPool();
                //插入取消交易代码
                _CancelTrade(pools);
                var sellPools = pools.Where(c => c.TradeType == (int)TradeTypeEnum.Sell);
                var buyPools = pools.Where(c => c.TradeType == (int)TradeTypeEnum.Buy);

                while (true)
                {
                    var sell = sellPools.Where(c => c.AgencyCount > 0).FirstOrDefault();
                    if (sell == null)
                    {
                        //无卖出
                        //启动定时涨价。
                        MarketManager.UpPriceStart();
                        break;
                    }

                    MarketManager.UpPriceStop();

                    //特殊处理提示：原来是判断有没有与卖出价格相同的，现在不这样判断，直接判断有没有比卖出价格大于等于的
                    var buy = buyPools.Where(c => c.AgencyCount > 0 & c.AgencyPrice >= sell.AgencyPrice).FirstOrDefault();

                    if (buy == null)
                    {
                        //无购买
                        break;
                    }
                    //这里做一点特殊处理，如果卖出用户得价格低于买入用户的价格，则以买入用户的高价格成交。
                    if (sell.AgencyPrice > buy.AgencyPrice)
                    {
                        //不能配对，跳出
                        break;
                    }
                    PairTrade(sell, buy);
                }
                if (WaitExecute)
                {
                    _Execute();
                }
            }
        }

        /// <summary>
        /// 配对,返回是否继续配对
        /// </summary>
        private static void PairTrade(StkWaitbargainpool sell, StkWaitbargainpool buy)
        {
            decimal userBalance = 0;
            UnitOfWork work = new UnitOfWork();
            try
            {
                BargainAgencyRepository agencyRep = new BargainAgencyRepository();
                decimal price = buy.AgencyPrice;
                decimal count = sell.AgencyCount > buy.AgencyCount ? buy.AgencyCount : sell.AgencyCount;

                #region 更改卖出信息

                sell.AgencyCount -= count;
                if (sell.AgencyCount == 0)
                {
                    rep.Delete(sell.Id, work);
                }
                else
                {
                    rep.Update(sell, work);
                }
                BargainFacility sellFacility = new BargainFacility(sell.AgencyId, price, count);
                sellFacility.Execute(work);
                userBalance = sellFacility.Balance;

                #endregion

                #region 更改买入信息

                buy.AgencyCount -= count;
                if (buy.AgencyCount == 0)
                {
                    rep.Delete(buy.Id, work);
                }
                else
                {
                    rep.Update(buy, work);
                }

                BargainFacility buyFacility = new BargainFacility(buy.AgencyId, price, count);
                buyFacility.Execute(work);


                #endregion

                work.Commit();

            }
            catch (Exception exp)
            {
                work.Rollback();
            }
            var p = MarketManager.Market.CurrentPrice;
            if (userBalance > 200 && userBalance > p*100)
            {

                decimal maxBuy = Math.Floor(userBalance/MarketManager.Market.CurrentPrice);
                BuyTradeFacility bf = new BuyTradeFacility(sell.UserId, maxBuy, p);
                bf.Execute();
                Execute();
            }
        }

        static WaitBargainPoolRepository rep = new WaitBargainPoolRepository();
        static IEnumerable<StkWaitbargainpool> GetPool()
        {
            LoadTimeStamp = DateTime.Now;
            return rep.GetAll();
        }


        #endregion



        #region 撤单

        static Queue<AgencyProxy> cancelQueue = new Queue<AgencyProxy>();

        public static void CancelTrade(string agencyId)
        {
            lock (cancelLock)
            {
                cancelQueue.Enqueue(new AgencyProxy() { AgencyId = agencyId, TimeStamp = DateTime.Now });
                Execute();
            }
        }

        static void _CancelTrade(IEnumerable<StkWaitbargainpool> pools)
        {
            //真正的撤单

            while (true)
            {
                if (cancelQueue.Count == 0) break;
                var p = cancelQueue.Peek();
                if (p.TimeStamp > LoadTimeStamp)
                    break;
                _CancelTrade2(pools,p);
                lock (cancelLock)
                {
                    cancelQueue.Dequeue();
                }
            }
        }
        static void _CancelTrade2(IEnumerable<StkWaitbargainpool> pools,AgencyProxy c)
        {
            var pool = pools.Where(m => m.AgencyId == c.AgencyId).FirstOrDefault();
            if (pool != null && pool.AgencyCount > 0)
            {
                CancelTradeFacility cf = new CancelTradeFacility(pool);
                cf.Execute();
            }
        }

        #endregion
    }
}
